
;; -------- lsp-mode --------
;; github.com/emacs-lsp/lsp-mode/#supported-languages
;; & mads-hartmann/bash-language-server config
(use-package lsp-mode
  :defer 3
  :commands lsp
  :init
  (setq-default lsp-restart 'auto-restart)
  (setq lsp-auto-guess-root t        ; Detect project root
	lsp-keep-workspace-alive nil ; Auto-kill LSP server
	lsp-prefer-flymake nil       ; Use lsp-ui and flycheck
	flymake-fringe-indicator-position 'right-fringe)
  ;; THE lsp hook now goes here.
  :hook
  (prog-mode . (lambda ()
		 (unless (derived-mode-p 'emacs-lisp-mode 'lisp-mode)
		   (lsp-deferred))))
  :bind (:map lsp-mode-map
	      ("C-c C-d" . lsp-describe-thing-at-point)))

(use-package lsp-ui
  :custom-face
  (lsp-ui-doc-background ((t (:background ,(face-background 'tooltip)))))
  (lsp-ui-sideline-code-action ((t (:inherit font-lock-type-face))))
  :init
  (setq lsp-ui-doc-enable t
	lsp-ui-doc-use-webkit nil
	lsp-ui-doc-delay 0.2
	lsp-ui-doc-border (face-foreground 'default)
	lsp-eldoc-enable-hover nil ;; Disable eldoc in minibuffer
	lsp-ui-sideline-enable t
	lsp-ui-sideline-show-hover nil
	lsp-ui-sideline-show-diagnostics nil
	lsp-ui-sideline-ignore-duplicate t
	lsp-ui-imenu-enable t
	lsp-ui-imenu-colors `(,(face-foreground 'font-lock-keyword-face)
			      ,(face-foreground 'font-lock-string-face)
			      ,(face-foreground 'font-lock-constant-face)
			      ,(face-foreground 'font-lock-variable-name-face)))
  :hook
  (lsp-mode . lsp-ui-mode)
  :config
  (setq lsp-ui-doc-max-height 20
	lsp-ui-doc-max-width 50
	lsp-ui-sideline-ignore-duplicate t
	lsp-ui-peek-always-show t)
  (add-to-list 'lsp-ui-doc-frame-parameters '(right-fringe . 8))
  ;; `C-g'to close doc
  (advice-add #'keyboard-quit :before #'lsp-ui-doc-hide)
  ;; Reset `lsp-ui-doc-background' after loading theme
  (add-hook 'after-load-theme-hook
	    (lambda ()
	      (setq lsp-ui-doc-border (face-foreground 'default))
	      (set-face-background 'lsp-ui-doc-background
				   (face-background 'tooltip)))))

(use-package company-lsp
  :init
  (setq company-lsp-cache-candidates 'auto)
  :config
  ;; WORKAROUND:Fix tons of unrelated completion candidates shown
  ;; when a candidate is fulfilled
  ;; @see https://github.com/emacs-lsp/lsp-python-ms/issues/79
  (add-to-list 'company-lsp-filter-candidates '(mspyls))

  (with-no-warnings
    (defun my-company-lsp--on-completion (response prefix)
      "Handle completion RESPONSE.

PREFIX is a string of the prefix when the completion is requested.

Return a list of strings as the completion candidates."
      (let* ((incomplete (and (hash-table-p response) (gethash "isIncomplete" response)))
	     (items (cond ((hash-table-p response) (gethash "items" response))
			  ((sequencep response) response)))
	     (candidates (mapcar (lambda (item)
				   (company-lsp--make-candidate item prefix))
				 (lsp--sort-completions items)))
	     (server-id (lsp--client-server-id (lsp--workspace-client lsp--cur-workspace)))
	     (should-filter (or (eq company-lsp-cache-candidates 'auto)
				(and (null company-lsp-cache-candidates)
				     (company-lsp--get-config company-lsp-filter-candidates server-id)))))
	(when (null company-lsp--completion-cache)
	  (add-hook 'company-completion-cancelled-hook #'company-lsp--cleanup-cache nil t)
	  (add-hook 'company-completion-finished-hook #'company-lsp--cleanup-cache nil t))
	(when (eq company-lsp-cache-candidates 'auto)
	  ;; Only cache candidates on auto mode. If it's t company caches the
	  ;; candidates for us.
	  (company-lsp--cache-put prefix (company-lsp--cache-item-new candidates incomplete)))
	(if should-filter
	    (company-lsp--filter-candidates candidates prefix)
	  candidates)))
    (advice-add #'company-lsp--on-completion :override #'my-company-lsp--on-completion)))

(provide '+lsp)
